package com.pt25.base.dep.es;


import com.pt25.base.constants.BaseConstants;
import com.pt25.base.util.CollectionUtil;
import com.pt25.base.util.StrUtil;
import jakarta.annotation.Resource;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.ssl.SSLContextBuilder;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.net.ssl.SSLContext;
import java.util.HashMap;
import java.util.Map;

@Configuration
class Es7Config {
    @Resource
    private EsProperties esProperties;

    private static final Map<String, RestHighLevelClient> restHighLevelClientCacheMap = new HashMap<>();

    @Bean("restHighLevelClientMap")
    Map<String, RestHighLevelClient> elasticsearchClients() {
        Map<String, RestHighLevelClient> restHighLevelClientMap = new HashMap<>();
        if (CollectionUtil.isNotEmpty(esProperties.getConfigs()) && esProperties.checkConfigs()) {
            esProperties.getConfigs().forEach((esConfig) -> {
                if ("7".equals(esConfig.getVersion())) {
                    String configStr = esConfig.toString();
                    if (null != restHighLevelClientCacheMap.get(configStr)) {
                        restHighLevelClientMap.put(esConfig.getName(), restHighLevelClientCacheMap.get(configStr));
                    } else {
                        try {
                            restHighLevelClientMap.put(esConfig.getName(), createClient(esConfig));
                            restHighLevelClientCacheMap.put(configStr, restHighLevelClientMap.get(esConfig.getName()));
                        } catch (Exception e) {
                            throw new RuntimeException("Failed to create ES client for cluster " + esConfig.getName(), e);
                        }
                    }
                }
            });
            if (null != restHighLevelClientMap.get(esProperties.getPrimary())) {
                restHighLevelClientMap.put(BaseConstants.DEFAULT, restHighLevelClientMap.get(esProperties.getPrimary()));
            }
        }
        return restHighLevelClientMap;
    }

    private RestHighLevelClient createClient(EsProperties.EsConfig esConfig) {
        String password = esConfig.getPassword();
        String username = esConfig.getUsername();
        RestClientBuilder restClientBuilder;

        String[] urls = esConfig.getUrls().split(",");
        HttpHost[] urlArr = new HttpHost[urls.length];
        for (int i = 0; i < urls.length; i++) {
            urlArr[i] = HttpHost.create(urls[i]);
        }
        if (StrUtil.isNotBlank(password) && StrUtil.isNotBlank(username)) {
            //创建凭证
            final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
            credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(esConfig.getUsername(), esConfig.getPassword()));
            // 创建低级客户端
            restClientBuilder = RestClient.builder(urlArr)
                    .setHttpClientConfigCallback(httpClientBuilder -> httpClientBuilder
                            .setDefaultCredentialsProvider(credentialsProvider)
                            .setSSLContext(getSSLContext()) // SSL配置
                            .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
                    )
                    .setRequestConfigCallback(requestConfigBuilder -> requestConfigBuilder
                            .setConnectTimeout(esConfig.getConnectTimeout())
                            .setSocketTimeout(esConfig.getSocketTimeout())
                    );
        } else {
            restClientBuilder = RestClient.builder(urlArr)
                    .setHttpClientConfigCallback(httpClientBuilder -> httpClientBuilder
                            .setSSLContext(getSSLContext()) // SSL配置
                            .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
                    )
                    .setRequestConfigCallback(requestConfigBuilder -> requestConfigBuilder
                            .setConnectTimeout(esConfig.getConnectTimeout())
                            .setSocketTimeout(esConfig.getSocketTimeout())
                    );
        }
        // 创建高级客户端
        return new RestHighLevelClient(restClientBuilder);
    }

    private SSLContext getSSLContext() {
        try {
            // 生产环境应使用正式证书（替换上面SSLContext部分）
//            Path trustStorePath = Paths.get("/path/to/truststore.p12");
//            char[] trustStorePassword = "password".toCharArray();
//            SSLContext sslContext = SSLContextBuilder.create()
//                    .loadTrustMaterial(trustStorePath, trustStorePassword)
//                    .build();
            // 生产环境应使用正式证书，此处为开发环境示例
            return SSLContextBuilder.create()
                    .loadTrustMaterial((chain, authType) -> true)
                    .build();
        } catch (Exception e) {
            throw new RuntimeException("Failed to create SSL context", e);
        }
    }
}
